#include "iic.h"

/**
 * PB10 SCL
 * PB11 SDA
 */

// IIC 初始化
void IIC_Init(void){
    // 1. 配置时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
    // 工作模式配置 通用开漏输出 CNF: 01  MODE: 11
    GPIOB->CRH |= (GPIO_CRH_MODE10_Msk | GPIO_CRH_MODE11_Msk);
    GPIOB->CRH &= ~(GPIO_CRH_CNF10_1 | GPIO_CRH_CNF11_1);
    GPIOB->CRH |= (GPIO_CRH_CNF10_0 | GPIO_CRH_CNF11_0);
}

// 起始信号
void IIC_Start(void){
    // SCL, SDA 高电平, 
    SCL_HIGHT;
    SDA_HIGHT;
    IIC_DELAY;

    // SDA 由高->低
    SDA_LOW;
    IIC_DELAY;
}

// 停止信号
void IIC_Stop(void){
    // SCL 高 SDA 低
    SCL_HIGHT;
    SDA_LOW;
    IIC_DELAY;

    // SDA 由低->高
    SDA_HIGHT;
    IIC_DELAY;
}

// 主机发出应答信号
void IIC_SendACK(void){
    // 1. SCL 低 SDA 高, 准备发出数据
    SCL_LOW;
    SDA_HIGHT;
    IIC_DELAY;

    // 2. SDA 由高->低 输出 应答
    SDA_LOW;
    IIC_DELAY;

    // 3. SCL 由低->高, 开始数据数据采样
    SCL_HIGHT;
    IIC_DELAY;

    // 3. 采样结束
    SCL_LOW;
    IIC_DELAY;

    // 释放当前的数据线
    SDA_HIGHT;
    IIC_DELAY;
}

// 主机发出非应答信号
void IIC_SendNACK(void){
    // 1. SCL 低 SDA 高, 准备发出数据
    SCL_LOW;
    SDA_HIGHT;
    IIC_DELAY;

    // 2. SDA 拉高保持不变
    // 3. SCL 由低->高, 开始数据数据采样
    SCL_HIGHT;
    IIC_DELAY;

    // 3. 采样结束
    SCL_LOW;
    IIC_DELAY;

}

// 主机接收应答信号
uint8_t IIC_ReceiveACK(void){
    //SCL 低, SDA 高电平, 释放数据总线
    SCL_LOW;
    SDA_HIGHT;
    IIC_DELAY;

    // SCL 由低->高, 开始数据采样
    SCL_HIGHT;
    IIC_DELAY;

    // 读取SDA 的电平
    uint16_t ack = READ_SDA;

    // SCL 由高->低, 结束数据采样
    SCL_LOW;
    IIC_DELAY;

    return ack? NACK : ACK;
}

// 主机发送一个字节的数据
void IIC_SendByte(uint8_t byte){
    for(uint8_t i = 0; i < 8; i++){
        // SCL 低, SDA 低
        SCL_LOW;
        SDA_LOW;
        IIC_DELAY;

        // 去字节的最高位 向 SDA 写入数据
        if(byte & 0x80){
            SDA_HIGHT;
        }else{
            SDA_LOW;
        }
        IIC_DELAY;

        // 时钟翻转, 数据采样
        SCL_HIGHT;
        IIC_DELAY;

        // SCL 由高->低, 结束数据采样
        SCL_LOW;
        IIC_DELAY;

        // 左移一位
        byte <<= 1;
    }
}

// 主机接收一个字节的数据
uint8_t IIC_ReceiveByte(void){
    uint8_t byte = 0;
    for(uint8_t i = 0; i < 8; i++){
        // SCL 低, SDA 高电平, 释放数据总线
        SCL_LOW;
        SDA_HIGHT;
        IIC_DELAY;

        // SCL 由低->高, 开始数据采样
        SCL_HIGHT;
        IIC_DELAY;

        // 读取SDA 的电平
        byte <<= 1;
        if(READ_SDA){
            byte |= 0x01;
        }

        // SCL 由高->低, 结束数据采样
        SCL_LOW;
        IIC_DELAY;
    }
    return byte;
}